
//Copyright 1997-2009 Syrinx Development, Inc.
//This file is part of the Syrinx Web Application Framework (SWAF).
// == BEGIN LICENSE ==
//
// Licensed under the terms of any of the following licenses at your
// choice:
//
//  - GNU General Public License Version 3 or later (the "GPL")
//    http://www.gnu.org/licenses/gpl.html
//
//  - GNU Lesser General Public License Version 3 or later (the "LGPL")
//    http://www.gnu.org/licenses/lgpl.html
//
//  - Mozilla Public License Version 1.1 or later (the "MPL")
//    http://www.mozilla.org/MPL/MPL-1.1.html
//
// == END LICENSE ==
using System;
using System.Collections;
using System.Xml;

namespace Swaf.Call
{
    /// <summary>
    /// FailoverCall is a CompositeCall type ICall implementation.  CompositeCalls contain one or more
    /// sub-call elements.  The FailoverCall call provides a mechanism to specify a primary, secondary, 
    /// tertiary, etc calling order.  When executed, the first non-disabled call in the list is executed.
    /// If that call fails it is disabled and the next call in the sequence is attempted until either
    /// all calls are disabled or a successfully call is made.  If all calls are disabled an exception is
    /// raised to the caller.
    /// </summary>
    public class FailoverCall : BaseCompositeCall
    {
        public FailoverCall(string id, XmlElement initInfo)
            : base(id, initInfo)
        {
        }

        public override object call(params object[] p)
        {
            bool success = false; // Assume it doesn't work in case all internalCallMembers are not enabled when attempting to call
            object results = null;

            loadInternalListIfEmpty();
            if (m_internalCalls.Count != 0)
            {
                Exception callException = null;
                foreach (internalCallMember entry in m_internalCalls)
                {
                    if (entry.enabled)
                    {
                        results = entry.makeCall(ref success, ref callException, p);
                        if (success)
                        {
                            break;
                        }
                        else if (callException != null)
                        {
                            if (!(callException is CallException))
                            {
                                throw new CallException(string.Format("Call to FailOver call has failed, method is '{0}'.", m_methodName), callException);
                            }

                            // If CallException was received then will move to the next call member and attempt it
                        }
                    }
                }
            
                // Ensure we got a valid execution
                if (!success)
                {
                    throw new CallException(string.Format("No enabled registered child calls to failover call.  Check configuration, last Exception: {0}", callException.ToString()), callException);
                }
            }

            return results;
        }
    }
}
